#include "IIC_1.h"
#include "Delay.h"

// SHT20设备地址
#define ADDR_RESS_SHT20 0x40 
// BH1750设备地址
#define ADDR_RESS_BH1750 0x1E
//脉搏
#define ADDR_RESS_PULSE 0x57

// I2C1初始化函数
void I2C_1_Init(void)
{
    // 启动时钟  RCC_APB1Periph_I2C1
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);

    // 配置GPIO
    GPIO_InitTypeDef GPIO_InitStruct;

    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;           // 复用
    GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;         // 开漏输出
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;           // 上拉
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;     // 速度
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6; // 确定引脚

    GPIO_Init(GPIOB, &GPIO_InitStruct);

    // 启动复用功能
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_I2C1);

    // 初始化 I2C1
    I2C_InitTypeDef I2C_InitStruct;

    // 选择通讯速度  选择 100kHz
    I2C_InitStruct.I2C_ClockSpeed = 100000;

    // 选择通讯模式  主模式
    I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;

    // 配置占空比  1:1
    I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;

    // 配置主机地址
    I2C_InitStruct.I2C_OwnAddress1 = 0x00;

    // 配置地址对从机地址的应答模式   选7位
    I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;

    // 应答控制   启用应答
    I2C_InitStruct.I2C_Ack = I2C_Ack_Enable;

    I2C_Init(I2C1, &I2C_InitStruct);

    // 使能I2C1
    I2C_Cmd(I2C1, ENABLE);
}

// I2C1发送起始信号函数
void I2C_1_Send_Start(uint8_t address, uint8_t r_w_cmd)
{
    // 总线是否空闲 
    while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)) {}
    // I2C_FLAG_BUSY 总线忙碌标识

    // 发送起始信号
    I2C_GenerateSTART(I2C1, ENABLE);
    // 发送起始信号
    // 当时钟线 高电平时 数据线产生一个下降沿

    // 等待主模式成功
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)) {}
    // I2C_CheckEvent 事件判定
    // I2C_EVENT_MASTER_MODE_SELECT   EV5 事件  
    // 事件说明： 等待DR寄存器清空

    // 发送地址
    I2C_Send7bitAddress(I2C1, address << 1, r_w_cmd);
    // 为啥要移位?
    // 因为地址位 7 位地址 我们的数据为 8 位数据
    //  这8位数据中最低位时 读写位 所以需要将address 进行移位 
    //  例如 设备地址 0100 0000   我们需要将其进行左移 1 位
    //    1000 000x    将 读写位数据 写入到 x位 中

    // 判断是否成功进入发送或接收模式
    if (r_w_cmd == I2C_Direction_Transmitter)
    {
        // 发送 EV6 事件
        while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) {}
        // I2C_CheckEvent 事件判定
        // I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED  发送的EV6事件
        // 判断是否进入发送模式
    }
    else {
        // 接收 EV6 事件
        while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)) {}
        // I2C_CheckEvent 事件判定
        // I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED  接收的 EV6 事件
        // 判断是否进入接收模式
    }
}

// 写命令函数
void WriteCmd(uint8_t address, uint8_t cmd)
{
    // 启动I2C 进入发送模式
    I2C_1_Send_Start(address, I2C_Direction_Transmitter);

    // 发送命令
    I2C_SendData(I2C1, cmd);

    // 等待发送完成
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)) {}

    // 等待 20us 进行延时
    Delay_us(20);

    // 发送停止信号
    I2C_GenerateSTOP(I2C1, ENABLE);
}

// 读数据函数
void ReadCmd(uint8_t address, char *buf, uint8_t len)
{
    // 启动I2C 进入接收模式
    I2C_1_Send_Start(address, I2C_Direction_Receiver);

    // 循环读取数据
    for (uint8_t i = 0; i < len; i++)
    {
        if (i == len - 1)
        {
            // 最后一个字节前，关闭应答信号，表示读取结束（NACK）
            I2C_AcknowledgeConfig(I2C1, DISABLE);
        }

        // 等待数据接收完成
        while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)) {}
        // I2C_EVENT_MASTER_BYTE_RECEIVED  EV7 数据   
        // 等待数据接收完成
        buf[i] = I2C_ReceiveData(I2C1);
    }

    // 回复ACK
    I2C_AcknowledgeConfig(I2C1, ENABLE);

    // 发送停止信号
    I2C_GenerateSTOP(I2C1, ENABLE);
}

// SHT20读温度函数
float SHT20_ReadTemperature(void)
{
    char data[3];
    uint16_t temp;
    // 发送温度请求命令
    WriteCmd(ADDR_RESS_SHT20, 0xF3);

    // 等待
    Delay_ms(85);

    // 接收  三个字节数据
    ReadCmd(ADDR_RESS_SHT20, data, 3);

    // 合并数据高低字节
    temp = ((uint16_t)data[0] << 8) | data[1];

    // 清除 低 2 位
    temp &= ~0x03;

    // 
    return -46.85 + 175.72 * temp / 65536.0;
}

// SHT20读湿度函数
float SHT20_ReadHumidity(void)
{
    char data[3];
    uint16_t temp;
    // 发送湿度请求命令
    WriteCmd(ADDR_RESS_SHT20, 0xF5);

    // 等待
    Delay_ms(85);

    // 接收  三个字节数据
    ReadCmd(ADDR_RESS_SHT20, data, 3);

    // 合并数据高低字节
    temp = ((uint16_t)data[0] << 8) | data[1];

    // 清除 低 2 位   
    temp &= ~0x03;

    return -6 + 125.0 * temp / 65536.0;
}

// BH1750读光照强度函数
float BH1750_ReadLightLevel(void)
{
    char data[2];
    uint16_t light;
    // 发送连续高分辨率模式命令
    WriteCmd(ADDR_RESS_BH1750, 0x10);

    // 等待测量完成
    Delay_ms(120);

    // 接收  两个字节数据
    ReadCmd(ADDR_RESS_BH1750, data, 2);

    // 合并数据高低字节
    light = ((uint16_t)data[0] << 8) | data[1];

    // 计算光照强度
    return light / 1.2;
}    

// 脉搏传感器读脉搏数据函数
int ReadPulseRate(void)
{
    char data[2];
    uint16_t pulse;
    // 假设发送读取脉搏数据的命令
    WriteCmd(ADDR_RESS_PULSE, 0x01); 

    // 等待测量完成，具体时间根据传感器确定
    Delay_ms(100); 

    // 接收  两个字节数据
    ReadCmd(ADDR_RESS_PULSE, data, 2);

    // 合并数据高低字节
    pulse = ((uint16_t)data[0] << 8) | data[1];

    return pulse;
}
